/*
  Copyright © 2010  José Cavalcante Reis Neto

      This file is part of Touché.

      Touché is free software: you can redistribute it and/or modify
      it under the terms of the GNU Lesser General Public License as published
      by the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.

      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU Lesser General Public License for more details.

      You should have received a copy of the GNU Lesser General Public License
      along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */

#include "photoelement.h"
#include <QGraphicsPixmapItem>
#include <QPushButton>
#include <QGridLayout>
#include <QGraphicsScene>
#include <QtDBus>
using namespace Touche;

#define DBUS_SHUTTER_RELEASE_BUTTON "/org/freedesktop/Hal/devices/platform_cam_launch"

const QDBusArgument & operator<<(QDBusArgument &arg, const Property &change)
{
    arg.beginStructure();
    arg << change.name << change.added << change.removed;
    arg.endStructure();
    return arg;
}

const QDBusArgument & operator>>(const QDBusArgument &arg, Property &change)
{
    arg.beginStructure();
    arg >> change.name >> change.added >> change.removed;
    arg.endStructure();
    return arg;
}

static const QString errorGst("Output window was closed");

static gboolean bus_call(GstBus *, GstMessage *msg, gpointer data)
{
    GMainLoop *loop = (GMainLoop *) data;

    switch (GST_MESSAGE_TYPE(msg))
    {
    case GST_MESSAGE_ERROR:
        {
            gchar *debug;
            GError *err;

            gst_message_parse_error (msg, &err, &debug);
            g_free (debug);

            if(errorGst == err->message)
                PhotoWidget::getInstance()->turnOff();

            g_error_free (err);

            g_main_loop_quit (loop);
            break;
        }
    default:;
    }
    return TRUE;
}

// class PhotoWidget

QScopedPointer<PhotoWidget> PhotoWidget::instance;

PhotoWidget *PhotoWidget::getInstance(Touche::Stage *stage, QWidget *parent)
{
    if(!instance)
        instance.reset(new PhotoWidget(stage, parent));
    return instance.data();
}

PhotoWidget::PhotoWidget(Touche::Stage *stage, QWidget *parent) :
        QDialog(parent, Qt::SubWindow),
        stage(stage),
        filter(false)
{
    parent->installEventFilter(this);

    qDBusRegisterMetaType< Property >();
    qDBusRegisterMetaType< QList<Property> >();
    QDBusConnection::systemBus().connect(QString(), DBUS_SHUTTER_RELEASE_BUTTON, "org.freedesktop.Hal.Device", "PropertyModified",
                                         this, SLOT(shutterPropertyModified(int, QList<Property>)));
}

PhotoWidget::~PhotoWidget()
{
    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(pipeline);
}

void PhotoWidget::setFilter(bool on)
{
    filter = on;
}

void PhotoWidget::turnOn()
{
    setFilter(true);

        pipeline = gst_pipeline_new("test-camera");


#ifdef Q_WS_MAEMO_5
        GstElement *cameraSrc = gst_element_factory_make("v4l2camsrc","Camera_src");
#else
        GstElement *cameraSrc = gst_element_factory_make("v4l2src","Camera_src");
#endif




        GstElement *cspFilter = gst_element_factory_make ("ffmpegcolorspace","filter");





        GstElement *screenSink = gst_element_factory_make("xvimagesink", "screenSink");


        //Link os itens do pipe
        gst_bin_add_many(GST_BIN(pipeline), cameraSrc, cspFilter, screenSink, NULL);


    //    caps = gst_caps_new_simple("video/x-raw-yuv",
    //                               "width",     G_TYPE_INT,        640,
    //                               "height",    G_TYPE_INT,        480,
    //                               "framerate", GST_TYPE_FRACTION, 15,  1,
    //                               NULL);
    //
    //    //link os elementos v4l2src , ffmpegcolorspace,video/x-raw-yuv
    //    gst_element_link_filtered(cameraSrc, filter, caps);
    //
    //    gst_caps_unref(caps);

        gst_element_link_many(cspFilter,screenSink,NULL);


        gst_element_link_many(cameraSrc,cspFilter,NULL);

        bus = gst_pipeline_get_bus(GST_PIPELINE (pipeline));
        gst_bus_add_watch(bus, bus_call, pipeline);
        gst_object_unref(bus);


        gst_element_set_state(pipeline,GST_STATE_PLAYING);
}

void PhotoWidget::turnOff()
{
    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(pipeline);
    setFilter(false);
    QDialog::done(0);
}

void PhotoWidget::shutterPropertyModified(int, QList<Property>)
{
    QDBusInterface propertyInterface("org.freedesktop.Hal", DBUS_SHUTTER_RELEASE_BUTTON, "org.freedesktop.Hal.Device", QDBusConnection::systemBus());
    bool pressed = propertyInterface.call("GetProperty", "button.state.value").arguments().at(0).toBool();
    if(pressed)
       takePhoto();
}

inline void PhotoWidget::takePhoto()
{
    PhotoElement *element = new PhotoElement;
    gst_element_set_state(pipeline,GST_STATE_READY);
    QString fileName("photo_" + element->m_id + ".jpg");

    pipelinephoto=gst_pipeline_new("photo pipeline");

    i = 0;

#ifdef Q_WS_MAEMO_5
    photoSrc = gst_element_factory_make("v4l2camsrc","photoSrc");
#else
    photoSrc = gst_element_factory_make("v4l2src","photoSrc");
#endif


    GstElement *photoFilter = gst_element_factory_make("ffmpegcolorspace","photoFilter");

    GstElement *photoSink   = gst_element_factory_make("jpegenc","Photo_sink");

    GstElement *sink = gst_element_factory_make("filesink","sink");
    g_object_set(G_OBJECT(sink),
                 "location", fileName.toStdString().c_str(),
                 NULL);



    gst_bin_add_many(GST_BIN(pipelinephoto),photoSrc,photoFilter,photoSink,sink,NULL);

    //    gst_element_link_filtered(cameraSrc, filter, caps);


    gst_element_link_many(photoSrc,photoFilter,photoSink,sink,NULL);


    g_print("palying");
    gst_element_set_state(pipelinephoto,GST_STATE_PLAYING);

    // TODO: diminuir este tempo, que está alto para o N900
    usleep(1350000);

    gst_element_set_state (pipelinephoto, GST_STATE_NULL);
    gst_object_unref (GST_OBJECT(pipelinephoto));

    gst_element_set_state(pipeline,GST_STATE_PLAYING);

    element->setFile(fileName);
    stage->addToGroup(element);

    gst_element_set_state(pipelinephoto, GST_STATE_NULL);
    gst_object_unref(pipelinephoto);
}

bool PhotoWidget::eventFilter(QObject *, QEvent *event)
{
    switch(event->type()){
    case QEvent::MouseButtonPress:
    case QEvent::MouseButtonRelease:
    case QEvent::MouseMove:
    case QEvent::MouseButtonDblClick:
    case QEvent::MouseTrackingChange:
        return filter;
    default:
        return false;
    }

}

// class PhotoElement

static const QString type("photo");

PhotoElement::PhotoElement() :
        m_item(new QGraphicsPixmapItem)
{
    m_null = false;
    emit contentsChanged();
}

PhotoElement::~PhotoElement()
{
    if(QFile::exists(fileName))
        QFile::remove(fileName);
}

QString PhotoElement::save() const
{
    return QString();
}

void PhotoElement::load(const QString &, const QString &file)
{
    m_item->setPixmap(QPixmap(file, "jpg", Qt::ColorOnly).scaled(120, 120, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
    fileName = file;
    m_null = false;
}

QString PhotoElement::file()
{
    return fileName;
}

const QString &PhotoElement::type() const
{
    return ::type;
}

QRectF PhotoElement::item(QGraphicsItem *parentItem) const
{
    m_item->setParentItem(parentItem);
    return m_item->boundingRect();
}

QVector<QString> PhotoElement::menuOptions() const
{
    return QVector<QString>();
}

void PhotoElement::onMenuActived(const QString &)
{
    return;
}

void PhotoElement::setFile(const QString &file)
{
    this->fileName = file;
    m_item->setPixmap(QPixmap(file).scaled(120, 120, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
}
